<?php
/**
 * 
 * To Enable this filter, put these lines into your filters.yml file:
 * 
 <pre>
	jfCacheHeaders:
	  class: jfCacheHeadersFilter
	  param:
	    cacheableEnvironments: [prod]
	    cacheableHttpStatusCodes: [200]
	    expireTime: 300
 </pre>
 *
 *
 * 
 * @package    jfCachePlugin
 * @subpackage lib
 * @author     Jonas Fischer <info@jonasfischer.net>
 * @version    SVN: $Id:$
 */
class jfCacheHeadersFilter extends sfFilter{

  /**
   * expireTime (in seconds)
   * Default value can be set in filters.yml
   * 
   * @var int
   */
	protected static $expireTime;

  /**
   * filter is enabled?
   * 
   * @var bool
   */
  protected static $enabled = null;
  
  protected static function log($message) {
  	$trace = debug_backtrace();
    $trace = array_slice($trace, 2, 5);

    foreach ($trace as $t) {
      $stack[] = (isset($t['class']) ? $t['class'].'::' : '').$t['function'];
    }
  	sfContext::getInstance()->getLogger()->log($message.' [Stack trace: '.print_r($stack, 1).']');
  }

  /**
   * Disable caching at runtime.
   * This will override the automatic checking mechanism based on symfony view cache config.
   * 
   * Set {@see self::$enabled} to false
   */
  public static function disable() {
		self::log(__METHOD__.': caching disabled');
    self::$enabled = false;
  }
  
  /**
   * Enable caching at runtime.
   * This will override the automatic checking mechanism based on symfony view cache config.
   * 
   * Set {@see self::$enabled} to true
   */
  public static function enable() {
  	self::log(__METHOD__.': caching enabled');
    self::$enabled = true;
  }
  
  /**
   * 
   * @return bool
   */
  protected function isEnabled() {
    return is_null(self::$enabled) ? $this->isRequestCacheableBasedOnSymfonyViewCache() : self::$enabled;
  }
  
  /**
   * Check if current request is cacheabl based on symfony view cache config:
   * Returns true if the current internal uri is cacheable (completely with action and layout).
   * False otherwise.
   * 
   * @return bool
   */
  protected function isRequestCacheableBasedOnSymfonyViewCache() {
  	$context = sfContext::getInstance();
  	$viewCacheManager = $context->getViewCacheManager();
  	$internalUri = $context->getRouting()->getCurrentInternalUri();
  	if ($viewCacheManager && $viewCacheManager->isCacheable($internalUri) && $viewCacheManager->withLayout($internalUri)) {
  		
  	  $expireTime = $viewCacheManager->getClientLifeTime($internalUri);
  		if(!$expireTime) {
  			$expireTime = $viewCacheManager->getLifetime($internalUri);	
  		}
  		
  		if($expireTime) {
  			self::setExpireTime($expireTime);
  		}
  		
  		return true;
  	}
  	
  	return false;
  }
  
	
  /**
   * add page content (html) to cache
   *
   * @param int $expireTime how many seconds this page will be cached
   *
   * @return void
   */
  protected function setCacheHttpHeaders($expireTime) {
    $this->context->getResponse()->addHttpMeta('Cache-Control', 'max-age='.$expireTime.', public, stale-while-revalidate=180, stale-if-error='.$expireTime*3);
    $this->context->getResponse()->setHttpHeader('Pragma', '');
  }

  /**
   * Set cache expire time in seconds
   * 
   * @param int $value
   */
  public static function setExpireTime($value)
  {
  	self::$expireTime = $value;
  }

  /**
   * Get cache expire time in seconds
   * 
   * @return int
   */
  protected function getExpireTime()
  {
  	if (empty(self::$expireTime)) {
  		self::$expireTime = $this->getParameter('expireTime', 0);
  	}
		return self::$expireTime;
  }

  /**
   * Execute the filter
   *
   * @param sfFilterChain $filterChain
   */
  public function execute ($filterChain) {
  	
    $filterChain->execute();
    
    if (self::isEnabled()
    		&& in_array($this->context->getConfiguration()->getEnvironment(), $this->getParameter('cacheableEnvironments', array('prod')))
    		&& in_array($this->context->getResponse()->getStatusCode(), $this->getParameter('cacheableHttpStatusCodes', array(200)))) {
		  $expireTime = $this->getExpireTime();
      $this->setCacheHttpHeaders($expireTime);
    }
//    $content = $this->context->getResponse()->getContent();
//	  $content = $this->addJavascriptDebugInfo($content, ($cachingActivated && !$suppressCaching && $buildCachedPage));
//    $this->context->getResponse()->setContent($content);
  }
  
//  /**
//   * Include cacheInfo javascript object in response html
//   *
//   * @param String $content
//   * @param bool $cachingEnabled
//   * 
//   * @return String [modified $content}
//   */
//  protected function addJavascriptDebugInfo($content, $cachingEnabled)
//  {
//  	$cacheInfo = array();
//  	$cacheInfo['cachingEnabled'] = $cachingEnabled;
//  	$cacheInfo['max_age'] = $this->getExpireTime();
//  	$cacheInfo['cache_date'] = date('c');
//  	$cacheInfo['expire_date'] = date('c', time()+$cacheInfo['max_age']);
//  	
//  	$script = '<script type="text/javascript">if (window.project) { project.cacheInfo = '.json_encode($cacheInfo).'; }</script>';
//  	
//  	return str_replace('</head>', $script.'</head>', $content);
//  }

}